package smallfrench.moteur.interp;

import smallfrench.moteur.biblio.err.ExceptionInterruption;
import smallfrench.moteur.interp.err.RException;
import smallfrench.moteur.noeuds.Noeud;

/**
 * Thread smallFrench
 * @author antoine1023
 *
 */
public class Tache extends Thread {

	/**
	 * Une référence vers le {@link ProcessusScript}.
	 * Ne doit jamais être nulle lorsque le thread tourne.
	 */
	protected ProcessusScript processusScript;

	private boolean mort = false;

	private final Evaluable evaluable;

	private RObjet valeurRetour;



	public Tache(Evaluable evaluable) {
		this.evaluable = evaluable;
	}



	public Tache(final IListeInstructions listeInstructions) {

		this.evaluable = new Evaluable() {

			@Override
			public RObjet evaluer() {

				Portee portee = listeInstructions.getPortee();
				RObjet valeurRetour = null;

				for (Noeud n : listeInstructions.getNoeuds()) {
					valeurRetour = n.evaluer(portee);
				}
				return valeurRetour;
			}
		};
	}



	@Override
	public final void run() {

		if (processusScript == null)
			throw new NullPointerException();

		try {

			valeurRetour = evaluable.evaluer();

		} catch (RException re) {

			mort = true;

			if (re.estUne(ExceptionInterruption.CLASSE))
				processusScript.enleverTache(this);
			else
				processusScript.intercepterRException(re);

			return;

		} catch (RuntimeException re) {
			mort = true;
			processusScript.intercepterRuntimeException(re);
			return;
		}

		mort = true;
		processusScript.enleverTache(this);
	}

	/**
	 * Doit être utilisée à la place de isAlive().
	 * @return <code>true</code> si la tâche est mort.
	 */
	public final boolean estMort() {
		return mort;
	}

	/**
	 * Cette méthode doit être utilisée uniquement par {@link ProcessusScript}
	 * @param ps
	 */
	final void setProcessusScript(ProcessusScript ps) {
		processusScript = ps;
	}

	public final ProcessusScript getProcessusScript() {
		return processusScript;
	}

	//	/**
	//	 *
	//	 * @param noeud
	//	 * @param portee
	//	 * @throws InterruptedException
	//	 */
	//	protected final RObjet evaluerNoeud(Noeud noeud, Portee portee)
	//			throws InterruptedException  {
	//
	//		try {
	//
	//			return noeud.evaluer(portee);
	//
	//		} catch (RException re) {
	//			if (re.estUne(ExceptionInterruption.CLASSE))
	//				throw new InterruptedException();
	//			processusScript.intercepterRException(re);
	//			throw new InterruptedException();
	//
	//		} catch (RThrowable t) {
	//			processusScript.intercepterRThrowable(t);
	//			throw new InterruptedException();
	//
	//		} catch (Exception e) {
	//			processusScript.intercepterThrowable(e);
	//			throw new InterruptedException();
	//		}
	//	}

	public RObjet getValeurRetour() {
		if (! mort)
			throw new IllegalStateException("La Tache " + toString() +
					" n'est pas mort");
		return valeurRetour;
	}

	@Override
	public String toString() {
		return "Tache" + getId();
	}

}
